<?php
namespace Monkey\Database\Driver;

use MonkeyException;

/**
 * Mysqli数据库驱动\Monkey\Database\Driver\Mysqli
 * @package    Monkey\Database\Driver
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\Database\Driver\Mysqli.php 版本号 2013-03-30 $
 */
class Mysqli implements _Interface
{
    /**
     * @var \mysqli
     */
    private $_linker;     //连接
    private $_sql;        //
    private $_prefix;
    /**
     * @var \mysqli_result
     */
    private $_result;    //
    private $_fetch_model=array(
        'assoc'=>MYSQLI_ASSOC,
        'num'=>MYSQLI_NUM,
        'both'=>MYSQLI_BOTH
    );
    private $_execute_true;
    public function __construct($config,$isTest=false) {
        if(!extension_loaded('mysqli')){
            MonkeyException::halt('没有安装mysqli驱动扩展,请先在php.ini中配置安装mysqli',1024,__FILE__,__LINE__);
        }
        if(!$isTest){
            $this->_linker= $this->connect($config,false);
        }
    }
    public function connect($config,$isTest=false){
        $linker=new \mysqli($config['host'],$config['username'],$config['password'],$config['dbname'],$config['port']);
        if(mysqli_connect_errno()){
            if($isTest)return notice(false,array('msg'=>mysqli_connect_error(),'code'=>mysqli_connect_errno()));
            else MonkeyException::halt('连接数据库时出错：'.mysqli_connect_error(),mysqli_connect_errno(),__FILE__,__LINE__);
        }
        if($isTest)return notice(true,array('msg'=>'连接成功','code'=>NULL));
        $this->_prefix=$config['prefix']?$config['prefix']:'';
        if(!is_null($this->_linker)){
            $this->clear();
            $this->_linker->close();
        }
        $linker->set_charset($config['charset']);
        $this->_linker=$linker;
        return true;
    }
    public function escape($data) {
        if (is_array($data)) return array_map(array($this,'escape'), $data);
        if (is_null($data)) return 'NULL';
        if (is_bool($data)) return $data ? '1' : '0';
        if (is_int($data)) return (int) $data;
        if (is_float($data)) return (float) $data;
        $data = sql_encode($data);
        return '"' . $this->_linker->real_escape_string($data) . '"'; // 注意mysqli_real_escape_string的参数位置
    }
    public function getPreFix(){
        return $this->_prefix;
    }
    public function transaction($type) {
        if($type===0 or $type=='begin'){
            $this->_linker->autocommit(0);
        }elseif($type===1 or $type=='commit'){
            $this->_linker->commit();
            $this->_linker->autocommit(1);
        }elseif($type===-1 or $type=='rollback'){
            $this->_linker->rollback();
            $this->_linker->autocommit(1);
        }
        return $this;
    }
    public function query($sql) {
        $this->clear();
        $this->_sql = preg_replace('/\{:(\S+?):\}/',$this->_prefix.'$1',$sql);
        $this->_result = $this->_linker->query($sql);
        $this->_execute_true = $this->_result === FALSE ? FALSE:TRUE;
        return $this;
    }
    public function isSuccess(){
        return $this->_execute_true;
    }
    public function resultCount() {
        if(!is_object($this->_result))return null;
        return $this->_result->num_rows;
    }
    public function resultAll($model=FETCH_ASSOC){
        if(!is_object($this->_result))return null;
        return sql_decode($this->_result->fetch_all($this->_fetch_model[$model]));
    }
    public function result($model=FETCH_ASSOC){
        if(!is_object($this->_result))return null;
        return sql_decode($this->_result->fetch_array($this->_fetch_model[$model]));
    }
    public function affectedRows() {
        return $this->_execute_true ? $this->_linker->affected_rows : NULL;
    }
    public function insertId() {
        return $this->_execute_true ? $this->_linker->insert_id : NULL;
    }
    public function lastSql(){
        return $this->_sql;
    }
    public function errorCode() {
        return $this->_linker->errno;
    }
    public function errorMessage() {
        return $this->_linker->error . '【sql：】' . $this->_sql;
    }
    public function clear() {
        $this->_sql = '';
        $this->_result = null;
        return $this;
    }
    public function destroy() {
        if(is_object($this->_linker))$this->_linker->close();
    }
}
